#include <unistd.h>
#include <stdio.h>
#include "MIServiceConnector.h"
#include "MIEvent.h"

PoliceThread::PoliceThread(MIServiceConnector* r)
 : auxiliary::Thread()
{
	ref = r;
}

void PoliceThread::run()
{
	unsigned int i;
	Collaboration::ListOfStrings lu;
	while(true)
	{
		lu = ref->mi_client->getDataAccessor()->nonUpdatedUsers(ref->application);
												
		for (i=0; i<lu.size(); i++)
		{
			ref->mi_client->getDataAccessor()->disconnectUser(ref->application, lu[i]);
			
			MIEvent evento(ref->handler->getCommunicator());
			evento.setMemberValue("mi_type", evento.fromInt(DISCONNECT));
			evento.setMemberValue("application", evento.fromString(ref->application));
			evento.setMemberValue("user", evento.fromString(lu[i]));

			ref->handler->push(evento);
		}
		
		sleep(60);
	}
}

KeepAliveThread::KeepAliveThread(MIServiceConnector* r)
 : auxiliary::Thread()
{
	ref = r;
}

void KeepAliveThread::run()
{
	while(true)
	{
		if (ref->connected)
		{
			ref->mi_client->getDataAccessor()->updateUserTime(ref->application, ref->user);
			sleep(10);
		}
		else
		{
			sleep(20);
		}
	}
}

MIServiceConnector::MIServiceConnector(const ::std::string& app, 
										const ::std::string& u, 
										const ::std::string& pass, 
										EventHandler* h, 
										MIClient* mc) : ListeningObject()
{
	user = u;
	password = pass;
	application = app;
	handler = h;
	mi_client = mc;
	login_allowed = false;
	connected = false;
	keep_alive_thread = new KeepAliveThread(this);
	police_thread = new PoliceThread(this);
	
	police_thread->start(); //inicia la hebra policia
}

MIServiceConnector::~MIServiceConnector()
{	
	delete keep_alive_thread;
	delete police_thread;
}

Collaboration::MIConnection MIServiceConnector::login()
{	
	Collaboration::MIConnection con = mi_client->getDataAccessor()->login(application, user, password);
	if (con.errorMessage.empty()) login_allowed = true;
	else login_allowed = false;
	
	return con;
}

bool MIServiceConnector::admin()
{
	return mi_client->getDataAccessor()->userInfo(application, user).isAdmin;
}

::std::string MIServiceConnector::connectUser()
{
	if (login_allowed)
	{
		role = mi_client->getDataAccessor()->connectUser(application, user);
	
		//se distribuye el evento de login si no hubo error
		if (!role.empty())
		{
			MIEvent evento(handler->getCommunicator());
			evento.setMemberValue("mi_type", evento.fromInt(LOGIN));
			evento.setMemberValue("application", evento.fromString(application));
			evento.setMemberValue("user", evento.fromString(user));
			evento.setMemberValue("role", evento.fromString(role));
		
			handler->push(evento);
			
			keep_alive_thread->start(); //se inicia la hebra keep_alive
		}
		
		connected = true;
	
		return role;
	}
	else
	{
		::std::string vacia;
		return vacia;
	}
}

void MIServiceConnector::disconnectUser()
{
	if (connected)
	{
		connected = false;
		::std::string vacia;
		role = vacia;
		login_allowed = false;
		
		mi_client->getDataAccessor()->disconnectUser(application, user);
		
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(DISCONNECT));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("user", evento.fromString(user));

		handler->push(evento);
		
		keep_alive_thread->cancel();
	}
}

Collaboration::MIConnection MIServiceConnector::changeConnectedUserRole(const ::std::string& newrole)
{
	Collaboration::MIConnection con = mi_client->getDataAccessor()->
										changeConnectedUserRole(application, user, newrole);
	
	//distribuir el evento en caso de no haber error
	if (con.errorMessage.empty())
	{
		role = newrole;
		
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(USER_ROLE_CHANGED));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("user", evento.fromString(user));
		evento.setMemberValue("role", evento.fromString(role));

		handler->push(evento);
	}
	
	return con;
}

Collaboration::ListOfStrings MIServiceConnector::roleUsers(const ::std::string& role_name)
{
	return mi_client->getDataAccessor()->roleUsers(application, role_name);
}

Collaboration::ListOfStrings MIServiceConnector::roleUsers()
{
	return mi_client->getDataAccessor()->roleUsers(application, role);
}

Collaboration::ListOfUsers MIServiceConnector::usersInfo()
{
	return mi_client->getDataAccessor()->usersInfo(application);
}

Collaboration::ListOfRoles MIServiceConnector::rolesInfo()
{
	return mi_client->getDataAccessor()->rolesInfo(application);
}

Collaboration::MIUser MIServiceConnector::userInfo()
{
	return mi_client->getDataAccessor()->userInfo(application, user);
}

Collaboration::MIUser MIServiceConnector::userInfo(const ::std::string& user_name)
{
	return mi_client->getDataAccessor()->userInfo(application, user_name);
}

Collaboration::MIRole MIServiceConnector::roleInfo()
{
	return mi_client->getDataAccessor()->roleInfo(application, role);
}

Collaboration::MIRole MIServiceConnector::roleInfo(const ::std::string& role_name)
{
	return mi_client->getDataAccessor()->roleInfo(application, role_name);
}

Collaboration::ListOfUsers MIServiceConnector::connectedUsers()
{
	return mi_client->getDataAccessor()->connectedUsersInfo(application);
}

Collaboration::ListOfStrings MIServiceConnector::components()
{
	return mi_client->getDataAccessor()->applicationComponents(application);
}

Collaboration::ListOfRoles MIServiceConnector::allowedRoles()
{
	return mi_client->getDataAccessor()->allowedRoles(application, user);
}

Collaboration::ListOfRoles MIServiceConnector::allowedRoles(const ::std::string& user_name)
{
	return mi_client->getDataAccessor()->allowedRoles(application, user_name);
}

bool MIServiceConnector::setUserComponentPermissions(const ::std::string& user_name, 
													const ::std::string& comp, 
													int level)
{
	bool correcto = mi_client->getDataAccessor()->
									setUserComponentPermissions(application, user_name, comp, level);
									
	if (correcto) //distribuir evento
	{
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(USER_COMPONENT_PERMISSIONS_CHANGE));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("user", evento.fromString(user_name));
		evento.setMemberValue("component", evento.fromString(comp));

		handler->push(evento);
	}
	
	return correcto;
}

bool MIServiceConnector::setUserComponentPermissions(const ::std::string& comp, int level)
{
	bool correcto = mi_client->getDataAccessor()->
									setUserComponentPermissions(application, user, comp, level);
									
	if (correcto) //distribuir evento
	{
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(USER_COMPONENT_PERMISSIONS_CHANGE));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("user", evento.fromString(user));
		evento.setMemberValue("component", evento.fromString(comp));

		handler->push(evento);
	}
	
	return correcto;
}

bool MIServiceConnector::setRoleComponentPermissions(const ::std::string& role_name, 
													const ::std::string& comp, 
													int level)
{
	bool correcto = mi_client->getDataAccessor()->
									setRoleComponentPermissions(application, role_name, comp, level);
									
	if (correcto) //distribuir evento
	{
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(ROLE_COMPONENT_PERMISSIONS_CHANGE));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("role", evento.fromString(role_name));
		evento.setMemberValue("component", evento.fromString(comp));

		handler->push(evento);
	}
	
	return correcto;
}

bool MIServiceConnector::setRoleComponentPermissions(const ::std::string& comp, int level)
{
	if (!role.empty())
	{
		bool correcto = mi_client->getDataAccessor()->
										setRoleComponentPermissions(application, role, comp, level);
									
		if (correcto) //distribuir evento
		{
			MIEvent evento(handler->getCommunicator());
			evento.setMemberValue("mi_type", evento.fromInt(ROLE_COMPONENT_PERMISSIONS_CHANGE));
			evento.setMemberValue("application", evento.fromString(application));
			evento.setMemberValue("role", evento.fromString(role));
			evento.setMemberValue("component", evento.fromString(comp));

			handler->push(evento);
		}
	
		return correcto;	
	}
	else return false;
}

int MIServiceConnector::getUserComponentPermissions(const ::std::string& comp)
{
	return mi_client->getDataAccessor()->getUserComponentPermissions(application, user, comp);
}

int MIServiceConnector::getUserComponentPermissions(const ::std::string& user_name, const ::std::string& comp)
{
	return mi_client->getDataAccessor()->getUserComponentPermissions(application, user_name, comp);
}	

int MIServiceConnector::getRoleComponentPermissions(const ::std::string& comp)
{
	return mi_client->getDataAccessor()->getRoleComponentPermissions(application, role, comp);
}

int MIServiceConnector::getRoleComponentPermissions(const ::std::string& role_name, const ::std::string& comp)
{
	return mi_client->getDataAccessor()->getRoleComponentPermissions(application, role_name, comp);
}

bool MIServiceConnector::newUser(const ::std::string& user_name, const ::std::string& pass, 
						const ::std::string& default_role, bool is_admin)
{
	bool correcto = mi_client->getDataAccessor()->
									newUser(application, user_name, pass, default_role, is_admin);
								
	if (correcto) //distribuir evento
	{
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(NEW_USER));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("user", evento.fromString(user_name));

		handler->push(evento);
	}

	return correcto;		
}

bool MIServiceConnector::newRole(const ::std::string& role_name)
{
	bool correcto = mi_client->getDataAccessor()->newRole(application, role_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(NEW_ROLE));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("role", evento.fromString(role_name));

		handler->push(evento);
	}

	return correcto;
}

bool MIServiceConnector::newUserAllowedRole(const ::std::string& user_name, const ::std::string& role_name)
{
 	bool correcto = mi_client->getDataAccessor()->
								newUserAllowedRole(application, user_name, role_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(NEW_ALLOWED_ROLE));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("user", evento.fromString(user_name));
		evento.setMemberValue("role", evento.fromString(role_name));

		handler->push(evento);
	}

	return correcto;
}

bool MIServiceConnector::newUserAllowedRole(const ::std::string& role_name)
{
	bool correcto = mi_client->getDataAccessor()->
								newUserAllowedRole(application, user, role_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(NEW_ALLOWED_ROLE));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("user", evento.fromString(user));
		evento.setMemberValue("role", evento.fromString(role_name));

		handler->push(evento);
	}

	return correcto;
}

bool MIServiceConnector::removeAllowedUserRole(const ::std::string& user_name, const ::std::string& role_name)
{
	bool correcto = mi_client->getDataAccessor()->
								removeAllowedUserRole(application, user_name, role_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(REMOVE_ALLOWED_ROLE));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("user", evento.fromString(user_name));
		evento.setMemberValue("role", evento.fromString(role_name));

		handler->push(evento);
	}

	return correcto;
}

bool MIServiceConnector::removeAllowedUserRole(const ::std::string& role_name)
{
	bool correcto = mi_client->getDataAccessor()->
								removeAllowedUserRole(application, user, role_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(REMOVE_ALLOWED_ROLE));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("user", evento.fromString(user));
		evento.setMemberValue("role", evento.fromString(role_name));

		handler->push(evento);
	}

	return correcto;
}

bool MIServiceConnector::removeUser(const ::std::string& user_name)
{
	bool correcto = mi_client->getDataAccessor()->removeUser(application, user_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(REMOVE_USER));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("user", evento.fromString(user_name));

		handler->push(evento);
	}

	return correcto;
}

bool MIServiceConnector::removeRole(const ::std::string& role_name)
{
	bool correcto = mi_client->getDataAccessor()->removeRole(application, role_name);
								
	if (correcto) //distribuir evento
	{
		MIEvent evento(handler->getCommunicator());
		evento.setMemberValue("mi_type", evento.fromInt(REMOVE_ROLE));
		evento.setMemberValue("application", evento.fromString(application));
		evento.setMemberValue("role", evento.fromString(role_name));

		handler->push(evento);
	}

	return correcto;
}

::std::string MIServiceConnector::userActualRole(const ::std::string& user_name)
{
	return mi_client->getDataAccessor()->userActualRole(application, user_name);
}

::std::string MIServiceConnector::userActualRole()
{
	return role;
}

void MIServiceConnector::commit()
{
	mi_client->getDataAccessor()->commit();
}
